Tutorial 3: Class-based Views

我们也可以使用基于类的视图编写我们的 API, 如我们所见, 这是一个有利的模式, 允许我们重用共同的功能, 使我们的代码不重复

使用基于类的视图重新我们的API

重构 views.py

from snippets.models import Snippet
from snippets.serializers import SnippetSerializer
from django.http import Http404
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status


class SnippetList(APIView):
    """
    List all snippets, or create a new snippet.
    """
    def get(self, request, format=None):
        snippets = Snippet.objects.all()
        serializer = SnippetSerializer(snippets, many=True)
        return Response(serializer.data)

    def post(self, request, format=None):
        serializer = SnippetSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

到目前为止, 一起都好. 它和之前的情况非常类似, 但我们可以更好的区分不同的 HTTP 方法, 我们需要继续更新 views.py 中的实例视图.

class SnippetDetail(APIView):
    """
    Retrieve, update or delete a snippet instance.
    """
    def get_object(self, pk):
        try:
            return Snippet.objects.get(pk=pk)
        except Snippet.DoesNotExist:
            raise Http404

    def get(self, request, pk, format=None):
        snippet = self.get_object(pk)
        serializer = SnippetSerializer(snippet)
        return Response(serializer.data)

    def put(self, request, pk, format=None):
        snippet = self.get_object(pk)
        serializer = SnippetSerializer(snippet, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def delete(self, request, pk, format=None):
        snippet = self.get_object(pk)
        snippet.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

同时, 我们需要用基于类的视图的方式, 重构 snippets/urls.py.

from django.conf.urls import url
from rest_framework.urlpatterns import format_suffix_patterns
from snippets import views

urlpatterns = [
    url(r'^snippets/$', views.SnippetList.as_view()),
    url(r'^snippets/(?P<pk>[0-9]+)/$', views.SnippetDetail.as_view()),
]

urlpatterns = format_suffix_patterns(urlpatterns)

Okay, 重构完成, 再运行开发服务器, 一切都和之前一样正常工作.

使用 mixins

使用基于类的视图的最大的好处就是, 允许我们快速的创建可复用的行为.

我们一直使用的 create/retrieve/update/delete 操作和我们创建的任何后端模型 API 很相似. 这些普遍的共同行为在 REST 框架的 mixin 类中实现.

让我们看看如何使用 mixin 类编写 views.py 模块.

from snippets.models import Snippet
from snippets.serializers import SnippetSerializer
from rest_framework import mixins
from rest_framework import generics

class SnippetList(mixins.ListModelMixin,
                  mixins.CreateModelMixin,
                  generics.GenericAPIView):
    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer

    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)

我们话一些时间测试这里发生了什么, 我们使用 GenericAPIView 创建我们的视图, 同时加入 ListModelMixinCreateModelMixin.

基础类提供核心功能, mixin 类提供 .list().create() 动作. 然后我们绑定 getpost 方法到合适的动作, 到目前为止, 已经变得足够简单.

class SnippetDetail(mixins.RetrieveModelMixin,
                    mixins.UpdateModelMixin,
                    mixins.DestroyModelMixin,
                    generics.GenericAPIView):
    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer

    def get(self, request, *args, **kwargs):
        return self.retrieve(request, *args, **kwargs)

    def put(self, request, *args, **kwargs):
        return self.update(request, *args, **kwargs)

    def delete(self, request, *args, **kwargs):
        return self.destroy(request, *args, **kwargs)

相似地. 我们使用 GenericAPIView 类提供核心功能, 添加 mixins 提供 .retrieve(), .update() and .destroy() 动作.

使用基于视图的一般类

我们使用 mixin 类使用比之前较少的代码编写视图, 但我们可以更进一步. REST 框架提供一个已经混入一般视图的集合, 我们可以用他们进一步缩减 views.py 模块.

from snippets.models import Snippet
from snippets.serializers import SnippetSerializer
from rest_framework import generics


class SnippetList(generics.ListCreateAPIView):
    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer


class SnippetDetail(generics.RetrieveUpdateDestroyAPIView):
    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer

Wow, 我们的代码看起来如此简介, 如此的Django

接下来我们学习 part 4 of the tutorial, 我们将学到如何为我们的 API 处理授权(authentication)和权限(permissions)